#include "signup.srpc.h"
#include "workflow/WFFacilities.h"
#include "../../include/CryptoUtil.h"
#include "workflow/MySQLResult.h"
#include <iostream>
#include <string>

#include <wfrest/HttpServer.h>
#include <chrono>
#include "ppconsul/agent.h"

using ppconsul::Consul;
using namespace ppconsul::agent;
using namespace wfrest;

using namespace srpc;
using namespace protocol;
using std::string;
using std::cout;
using std::endl;

static WFFacilities::WaitGroup wait_group(1);

void sig_handler(int signo)
{
	wait_group.done();
}

void mysql_callback(WFMySQLTask* task)
{
	// 获取原函数的resp回复报文，可在下面直接设置回复报文内容
	SignupResponse *response = (SignupResponse *)task->user_data;

    // 1. 判断任务是否成功, 不成功回复 不成功 与 错误信息
    int state = task->get_state();
    if (state != WFT_STATE_SUCCESS) {
		string err_string = WFGlobal::get_error_string(state, task->get_error());
        cout << "[Error]: " <<  err_string << "\n\n";
        response->set_success(false);
		response->set_message("signup " + err_string);
		return ;
    }

	// 2. 处理结果集
    MySQLResponse* resp = task->get_resp();
    MySQLResultCursor cursor { resp };
    if (cursor.get_cursor_status() == MYSQL_STATUS_OK) {
        // INSERT 语句执行成功
        cout << "Signup OK.\n\n";
		response->set_success(true);
    }
}

class SignupServiceImpl : public Signup::Service
{
public:

	void Signup(SignupRequest *request, SignupResponse *response, srpc::RPCContext *ctx) override
	{
		cout << "\nIn Signup:" << endl;

		// 解析客户端的请求参数
		string username = request->username();
		string password = request->password();

		cout << "[username]: " << username << "   [password]: " << password << endl;

		// 服务端的业务逻辑
		// 1. 生成随机盐值
		// 2. 对密码哈希
		// 3. 将用户信息存入数据库

        // 生成随机盐值
        string salt = CryptoUtil::generate_salt();

        cout << "[salt]: " << salt << endl;

        // 对密码哈希
        string hash_password = CryptoUtil::hash_password(password, salt);

        cout << "[hash_password]: " << hash_password << endl; 

		// 将用户信息存入数据库
		//   1. 创建任务
		const string url = "mysql://root@localhost/cpp65";
		const int retry_max = 3;
		WFMySQLTask* task = WFTaskFactory::create_mysql_task(url, retry_max, mysql_callback);    
	
		//   2. 设置请求
		string sql = "INSERT INTO tbl_user (username, password, salt) VALUES ('" + 
                       username + "', '" + hash_password + "', '" + salt + "')";
		MySQLRequest* req = task->get_req();
		req->set_query(sql);
		cout << "[MYSQL] " << sql << endl;

		//   3. 设置 user_data 为 SignupResponse *response，传入回调函数
		task->user_data = (void*)response;

		//   4. 将WFMySQLTask放入SeriesWork中
        ctx->get_series()->push_back(task);
	}
};


void timer_callback(WFTimerTask* task)
{
    SeriesWork* series = series_of(task);
    Agent* agent = static_cast<Agent*>(series->get_context());

    // 发送心跳包
    agent->servicePass("signup");
    // 创建另一个定时任务
    WFTimerTask* nextTask = WFTaskFactory::create_timer_task(7, 0, timer_callback);
    series->push_back(nextTask);
}


int main()
{
	GOOGLE_PROTOBUF_VERIFY_VERSION;
	unsigned short port = 4817;
	SRPCServer server;

	SignupServiceImpl signup_impl;
	server.add_service(&signup_impl);
	server.start(port);

	HttpServer hserver {};
	hserver.start(port);

	// 指定注册中心 Consul 的ip地址，端口和数据中心
	Consul consul { "http://127.0.0.1:8500", ppconsul::kw::dc="dc1" };
	// 创建代理
	Agent agent { consul };
	// 注册服务 
	agent.registerService(
		kw::id = "signup",
		kw::name = "UserService",
		kw::address = "127.0.0.1",
		kw::port = 4817,
		kw::check = TtlCheck(std::chrono::seconds{ 10 })
	);
	
	// 定时发送心跳包
	WFTimerTask* timerTask = WFTaskFactory::create_timer_task(7, 0, timer_callback);

	SeriesWork* series = Workflow::create_series_work(timerTask, nullptr);
	series->set_context(&agent);    // 设置序列的上下文
	series->start();


	wait_group.wait();

	server.stop();
	hserver.stop();
	google::protobuf::ShutdownProtobufLibrary();
	return 0;
}
